<!DOCTYPE html>
<!--
Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<!--
The chart-tooltip element is the box that is shown when you hover over or click
on a point on a graph. It shows more detailed information about the point that
was just clicked.
-->

<link rel="import" href="/components/iron-icon/iron-icon.html">
<link rel="import" href="/components/iron-icons/iron-icons.html">
<link rel="import" href="/components/paper-card/paper-card.html">

<link rel="import" href="/dashboard/elements/alert-remove-box.html">
<link rel="import" href="/dashboard/elements/bisect-button.html">
<link rel="import" href="/dashboard/elements/dialog-container.html">
<link rel="import" href="/dashboard/elements/trace-button.html">
<link rel="import" href="/dashboard/elements/triage-dialog.html">

<dom-module id="chart-tooltip">
  <style>
    #tooltip {
      width: 360px;
      position: relative;
      margin: 10px;
      padding: 0px;
    }

    #tooltip .card-content {
      padding: 15px;
      overflow-y: auto;
      max-height: 250px;
    }

    #close-button {
      float: right;
    }

    iron-icon: {
      color: black;
    }

    iron-icon:active {
      color: #f09300;
    }
  </style>

  <template>
    <dialog-container id="container">
      <triage-dialog id="triage"
                     xsrf-token="{{xsrfToken}}"
                     alerts="{{alerts}}"></triage-dialog>
      <paper-card id="tooltip" alwaysOnTop elevation=4>
        <style>
          #test-name {
            word-wrap: break-word;
          }

          div:not(:last-of-type) {
            margin-bottom: 15px;
          }
        </style>

        <div class="card-content">
          <template is="dom-repeat" items="{{alerts}}">
            <div class="important">
              <b>Alert information:</b><br>
              Median of segment before: {{item.median_before_anomaly}}<br>
              Median of segment after: {{item.median_after_anomaly}}<br>
              Relative change: {{item.percent_changed}}<br>
            </div>
          </template>

          <div id="test-name">
            Test: {{parentPath}}/<b>{{seriesName}}</b>
          </div>

          <div>
            Value: <b>{{value}}</b> <span hidden$={{!stddev}}>(± {{stddev}})</span>
          </div>

          <div>
            <span hidden$={{!pointId}}>Point ID: {{pointId}}</span><br>
            <span hidden$={{!timestamp}}>Time added: {{timestamp}}</span><br>
            <span hidden$={{!botId}}>Test Bot(s): {{botId}}</span><br>
            <span hidden$={{!osDetailVers}}>OS Version: {{osDetailVers}}</span>
          </div>

          <template is="dom-if" if="{{bugId}}">
            <div>
              <span hidden$={{alertInvalidOrIgnored}}>Bug ID:
                <b>
                  <a target="_blank" href="http://crbug.com/{{projectId}}/{{bugId}}">
                    {{projectId}}:{{bugId}}
                  </a>
                </b>
              </span>

              <span hidden$="{{bugNotInvalid(bugId)}}">Invalid alert</span>
              <span hidden$="{{bugNotIgnored(bugId)}}">Ignored alert</span>
              <span hidden$="{{!recovered}}">Recovered alert</span>
              <alert-remove-box key="{{alertKey}}" xsrf-token="{{xsrfToken}}" on-untriaged="onUntriaged">
              </alert-remove-box><br>
              <a href="/group_report?keys={{alertKey}}">View alert graph</a>
            </div>
          </template>

          <div>
            <template is="dom-repeat" items={{revisions}}>
              {{item.name}}<template is="dom-if" bind if="{{item.displayStart}}"> range</template>:
              <b>
                <a href="{{item.url}}" on-click="onRevisionRangeClick">
                  <template is="dom-if" bind if="{{item.displayStart}}">{{item.displayStart}} - </template>
                  {{item.displayEnd}}
                </a>
              </b><br>
            </template>
          </div>

          <div>
            <span class="annotation-link"><a href="/group_report?rev={{pointId}}" target="_blank">See all performance changes at {{pointId}}</a></span><br /><br />
            <template is="dom-repeat" items={{links}}>
              <span class="annotation-link"><a href="{{item.url}}" target="_blank">{{item.text}}</a>
              <iron-icon icon="content-copy" title="Copy link" on-click="onCopyToClipboard"></iron-icon>
              </span><br />
            </template>
          </div>
        </div>

        <div class="card-actions">
          <bisect-button dialog-confirm xsrf-token="{{xsrfToken}}"
                         bug-id="{{bugId}}"
                         project-id="{{projectId}}"
                         bisect-info="{{bisectInfo}}"
                         alerts="[[alerts]]"></bisect-button>
          <trace-button dialog-confirm xsrf-token="{{xsrfToken}}"
                        bug-id="{{bugId}}"
                        trace-info="{{bisectInfo}}"></trace-button>
          <paper-button id="close-button" raised dismissive on-click="close">Close</paper-button>
        </div>

      </paper-card>
    </dialog-container>
  </template>
</dom-module>
<script>
'use strict';
Polymer({
  is: 'chart-tooltip',
  properties: {
    alerts: {
      notify: true,
      observer: 'alertsChanged'
    },
    bugId: {
      value: null,
      notify: true
    },
    projectId: {
      type: String,
      value: ''
    },
    hideStddev: {
      type: Boolean,
      value: true
    },
    hideStdioUri: {
      type: Boolean,
      value: true
    },
    links: { notify: true },
    pointId: { notify: true },
    revisions: {
      type: Array,
      value() {
        return [];
      },
      notify: true
    },
    stddev: { value: null },
    stdioUri: { value: null },
    testPath: {
      notify: true,
      observer: 'testPathChanged'
    },
    traceName: { value: null },
    value: {
      value: null,
      notify: true
    },
    xsrfToken: { notify: true }
  },

  testPathChanged() {
    if (this.testPath) {
      const parts = this.testPath.split('/');
      this.seriesName = parts.pop();
      this.parentPath = parts.join('/');
    }
  },

  /**
    * Shows the CL descriptions for the given revision range.
    */
  onRevisionRangeClick(event, detail) {
    window.open(
        event.currentTarget.href, 'changelog', 'width=1000,height=1000');
    event.preventDefault();
  },

  copyTextToClipboard(text) {
    const textArea = document.createElement('textarea');
    textArea.value = text;
    document.body.appendChild(textArea);
    textArea.select();
    let successful = false;
    try {
      successful = document.execCommand('copy');
    } catch (e) {
      successful = false;
    }
    document.body.removeChild(textArea);
    return successful;
  },

  onCopyToClipboard(event) {
    const link = event.model.item.url;
    const success = this.copyTextToClipboard(link);
    if (!success) {
      window.prompt('Could not copy automatically, select and copy', link);
    }
  },

  /**
    * Updates the display of the triage-dialog.
    * This method is called whenever the value of this.alerts changes,
    * e.g. by chart-container when an alert is triaged.
    */
  alertsChanged() {
    // The triage-dialog should be shown when there is some non-triaged
    // alert, and hidden otherwise.
    if (this.alerts && this.alerts.length) {
      this.$.triage.show();
    } else {
      this.$.triage.close();
    }
  },

  /**
    * Fires a 'triaged' event, which should be caught in chart-container.
    */
  onUntriaged(event, detail) {
    this.fire('triaged', {
      'alerts': this.triagedAlerts,
      'bugid': null,
      'projectid': null
    });
  },

  open() {
    const oldLeft = this.$.container.offsetLeft;
    const oldTop = this.$.container.offsetTop;
    openAtPosition(oldTop, oldLeft);
  },

  close() {
    if (this.$.container.opened) {
      this.$.container.close();
    }
  },

  openAtPosition(top, left) {
    this.$.container.updatePositionFromCoords(top, left);
    if (!this.$.container.opened) {
      this.$.container.open();
    }
  },

  bugNotInvalid(bugId) {
    return bugId != -1;
  },
  bugNotIgnored(bugId) {
    return bugId != -2;
  }
});
</script>
